import requests
import time
from pathlib import Path
from typing import Dict, Any, Optional, List, Union
from .base_sender import BaseReportSender

class WeComSender(BaseReportSender):
    """企业微信发送器"""
    
    def __init__(self, config: Dict[str, Any]):
        """初始化企业微信发送器
        
        Args:
            config: 企业微信配置信息，包含以下字段：
                - corp_id: 企业ID
                - agent_id: 应用ID
                - secret: 应用密钥
                - to_user: 接收消息的用户ID列表
                - to_party: 接收消息的部门ID列表（可选）
                - to_tag: 接收消息的标签ID列表（可选）
                - safe: 是否保密消息（可选，默认0）
                - enable_duplicate_check: 是否开启重复消息检查（可选，默认0）
                - duplicate_check_interval: 重复消息检查时间间隔（可选，默认1800秒）
        """
        super().__init__(config)
        self.required_keys = ['corp_id', 'agent_id', 'secret', 'to_user']
        self._access_token = None
        self._token_expires_at = 0
        
    def send_report(self, report_path: Path, title: str, content: Optional[str] = None) -> bool:
        """发送测试报告到企业微信
        
        Args:
            report_path: 报告文件路径
            title: 消息标题
            content: 消息内容（可选）
            
        Returns:
            是否发送成功
        """
        if not self._validate_config(self.required_keys):
            return False
            
        try:
            # 获取访问令牌
            if not self._get_access_token():
                return False
                
            # 获取文件信息
            file_info = self._get_file_info(report_path)
            
            # 上传报告文件
            media_id = self._upload_file(report_path)
            if not media_id:
                return False
                
            # 构建消息内容
            message = self._build_message(title, content, file_info, media_id)
            
            # 发送消息
            return self._retry_on_failure(self._send_message, message)
            
        except Exception as e:
            self.logger.error(f"Failed to send test report to WeCom: {str(e)}")
            return False
            
    def _build_message(self, title: str, content: Optional[str], 
                      file_info: Dict[str, Any], media_id: str) -> Dict[str, Any]:
        """构建消息内容
        
        Args:
            title: 消息标题
            content: 消息内容
            file_info: 文件信息
            media_id: 媒体文件ID
            
        Returns:
            消息对象
        """
        message = {
            "touser": "|".join(self.config['to_user']),
            "msgtype": "file",
            "agentid": self.config['agent_id'],
            "file": {
                "media_id": media_id
            },
            "safe": self.config.get('safe', 0),
            "enable_duplicate_check": self.config.get('enable_duplicate_check', 0),
            "duplicate_check_interval": self.config.get('duplicate_check_interval', 1800)
        }
        
        # 添加部门接收者
        if 'to_party' in self.config:
            message['toparty'] = "|".join(self.config['to_party'])
            
        # 添加标签接收者
        if 'to_tag' in self.config:
            message['totag'] = "|".join(self.config['to_tag'])
            
        return message
        
    def _get_access_token(self) -> bool:
        """获取企业微信访问令牌
        
        Returns:
            是否获取成功
        """
        # 检查令牌是否过期
        if self._access_token and time.time() < self._token_expires_at:
            return True
            
        try:
            response = requests.get(
                "https://qyapi.weixin.qq.com/cgi-bin/gettoken",
                params={
                    "corpid": self.config['corp_id'],
                    "corpsecret": self.config['secret']
                }
            )
            response.raise_for_status()
            result = response.json()
            
            if result.get('errcode') == 0:
                self._access_token = result.get('access_token')
                # 设置令牌过期时间（提前5分钟过期）
                self._token_expires_at = time.time() + result.get('expires_in', 7200) - 300
                return True
            else:
                self.logger.error(f"Failed to get access token: {result.get('errmsg')}")
                return False
                
        except Exception as e:
            self.logger.error(f"Failed to get access token: {str(e)}")
            return False
            
    def _upload_file(self, file_path: Path) -> Optional[str]:
        """上传文件到企业微信
        
        Args:
            file_path: 文件路径
            
        Returns:
            媒体文件ID
        """
        try:
            with open(file_path, 'rb') as f:
                files = {
                    'media': f
                }
                response = requests.post(
                    f"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={self._access_token}&type=file",
                    files=files
                )
                response.raise_for_status()
                result = response.json()
                
                if result.get('errcode') == 0:
                    return result.get('media_id')
                else:
                    self.logger.error(f"Failed to upload file: {result.get('errmsg')}")
                    return None
                    
        except Exception as e:
            self.logger.error(f"Failed to upload file: {str(e)}")
            return None
            
    def _send_message(self, message: Dict[str, Any]) -> bool:
        """发送消息
        
        Args:
            message: 消息对象
            
        Returns:
            是否发送成功
        """
        response = requests.post(
            f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={self._access_token}",
            json=message
        )
        response.raise_for_status()
        result = response.json()
        
        if result.get('errcode') == 0:
            self.logger.info("Successfully sent test report to WeCom")
            return True
        else:
            self.logger.error(f"Failed to send test report to WeCom: {result.get('errmsg')}")
            return False 